package org.shiro.Interceptor;

import org.apache.shiro.authc.UnknownAccountException;
import org.shiro.annotation.PassToken;
import org.shiro.annotation.ValidateToken;
import org.shiro.entity.User;
import org.shiro.service.UserService;
import org.shiro.util.JwtUtil;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * @author 党怡承
 * @version 1.0
 * @date 2021-04-24 16:25
 */
public class AuthenticationInterceptor implements HandlerInterceptor {
  @Resource private UserService userService;

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handle) {
    String token = request.getHeader("token");
    if (!(handle instanceof HandlerMethod)) {
      return true;
    }

    HandlerMethod handlerMethod = (HandlerMethod) handle;
    Method method = handlerMethod.getMethod();
    if (method.isAnnotationPresent(PassToken.class)) {
      PassToken passToken = method.getAnnotation(PassToken.class);
      if (passToken.required()) {
        return true;
      }
    }

    if (method.isAnnotationPresent(ValidateToken.class)) {
      ValidateToken validateToken = method.getAnnotation(ValidateToken.class);
      if (validateToken.required()) {
        if (token == null) {
          throw new RuntimeException("当前请求头中无token");
        }
        String userName;
        try {
          userName = JwtUtil.getUsername(token);
        } catch (Exception e) {
          throw new RuntimeException("解析token异常");
        }
        User user = userService.findUserByName(userName);
        if (user == null) {
          throw new UnknownAccountException("当前用户不存在");
        }
        try {
          JwtUtil.verify(token, user.getUsername());
        } catch (Exception e) {
          throw new RuntimeException("当前token已过期");
        }
        return true;
      }
    }
    return true;
  }
}
